// 11. 模板

/**
 * 1. 函数模板
 *    语法
 *      template <class X>
 *      return_type (X a,X b,type c,...){}
 * 
 *     注意：
 *        1. 可以通过class或typename指定模板类型形参，形参名由用户指定
 *        2. 多个类型形参以,分隔
 *        3. #11 类型形参默认值跟函数默认值设置类似，从右往左。它是把类型默认值和参数默认值分开。如果定义模板函数参数默认值，则类型和值都要设置默认值
 * 
 * 2. 类模板
 *      语法:
          template <typename X>
          class class_name{
            public:
              X a;// 类内使用模板类型形参
          }
          // 类外使用模板形参类型
          template <typename X>
          return_type class_name<X>::fun(){

          }
        
 *      注意:
 *        1. 可以通过class或typename指定模板类型形参，形参名由用户指定
 *        2. 多个类型形参以,分隔
 *        3. #21 可以指定非类型形参（即内置类型形参，只能是整型、指针、引用），它是const类型
 *        4. 类型形参和非类型形参都可以有默认值
 *          
 *  
 * 扩展：
 *    1. typename 其他作用
 *          告诉编译器typename 后面跟的字符串是一个类型。
 *          示例（使用类中定义的类型）：
              class X
              {
                public:
                typedef mytype int;
              };

              typedef typename X::mytype xxx;
*/
#include <iostream>

#define __mark 21

#if 11 == __mark

/**
 * #11 函数模板-类型形参默认值
*/
template <class T1, typename T2 = int, typename T3 = char>
void fun(T1 a, T2 b = 'c', T3 c = 65 + 32)
{
  std::cout << "a: " << a << " b: " << b << " c: " << c << std::endl;
}
int main(void)
{
  // fun(2.1, 'c', 2);
  fun(2.1, 'c');
  fun(2.1);
  printf("-----------end-------------\n");
  return 0;
}
#elif 21 == __mark

/**
 * #21 类模板--非类型参数
*/

template <class T1 = int, size_t _a = 2, class T2 = char>
class Test
{
public:
  T1 a;
  void print_a();
};

template <class T1, size_t _a, class T2>
void Test<T1, _a, T2>::print_a()
{
  T1 a = 65;
  T2 b = 'a';
  std::cout << "a: " << a << " _a: " << _a << " b: " << b << std::endl;
}

int main(void)
{
  // Test<> t1;
  // Test<char, 1, int> t1;
  const int a = 1;
  Test<char, a, int> t1;
  t1.print_a();
  printf("-----------end-------------\n");
  return 0;
}
#endif